package app

import (
	"context"
	"fmt"
	"net/http"
	"strings"

	"github.com/glennliao/apijson-go/config"
	"github.com/glennliao/apijson-go/consts"
	"github.com/gogf/gf/v2/util/gconv"
	"github.com/samber/lo"
)

const (
	表用户   = "User"
	表书签   = "Bookmark"
	表书签使用 = "BookmarkUse"
	表书签分类 = "BookmarkCate"
	表群组   = "Groups"
	表群组成员 = "GroupUser"
)

const 用户ID键 = "userId"

type 当前用户 struct {
	用户ID string
}

const 角色群组成员 = "GroupUser"
const 角色群组管理员 = "GroupAdmin"

func 角色权限(ctx context.Context, 请求 config.M角色请求) (string, error) {
	_, 存在 := ctx.Value(用户ID键).(*当前用户)

	if !存在 {
		return consts.W未登录用户, nil // 未登录
	}

	if 请求.J节点角色 == "" {
		switch 请求.F访问名称 {
		case 表用户:
			return consts.S数据拥有者, nil
		}
	} else {
		switch 请求.F访问名称 {
		case 表用户:
			if 请求.J节点角色 == consts.D登录用户 {
				return consts.S数据拥有者, nil
			}

		case 表书签, 表书签使用:
			if 请求.J节点角色 == consts.D登录用户 {
				请求.J节点角色 = consts.S数据拥有者
			}

			if lo.Contains([]string{consts.S数据拥有者, 角色群组成员}, 请求.J节点角色) {
				return 请求.J节点角色, nil
			}

			return consts.J拒绝访问, nil // 非拥有的角色

		default:
			return 请求.J节点角色, nil
		}
	}

	return consts.D登录用户, nil
}

func 访问条件(ctx context.Context, 请求 config.T条件请求, 条件 *config.T条件结果) (错误 error) {
	用户, 存在 := ctx.Value(用户ID键).(*当前用户)
	if !存在 {
		条件.T添加条件("1", 2)
		return nil
	}

	switch 请求.F访问名称 {
	case 表用户:
		if 请求.J节点角色 == consts.S数据拥有者 {
			条件.T添加条件("user_id", 用户.用户ID)
		}
	case 表书签使用:
		条件.T添加条件("user_id", 用户.用户ID)

	case 表书签分类:
		条件.T添加原始条件("group_id in (select group_id from group_user where user_id = ?)", 用户.用户ID)
	case 表书签:
		条件.T添加条件("group_id", 用户.用户ID)
		if 请求.Q请求方法 == http.MethodGet {
			if 值, 存在 := 请求.J节点请求数据["q"]; 存在 {
				delete(请求.J节点请求数据, "q")

				查询词 := fmt.Sprintf("%s", gconv.String(值))
				词语 := strings.Split(查询词, " ")

				sql := ""
				var 参数 []string
				for 索引, 词 := range 词语 {
					if 索引 > 0 {
						sql += " and "
					}
					sql += fmt.Sprintf("(lower(title) like ? or lower(url) like ? or lower(remark) like ?)")
					词 = strings.ToLower(词)
					参数 = append(参数, "%"+词+"%", "%"+词+"%", "%"+词+"%")
				}

				if len(参数) > 0 {
					条件.T添加原始条件("("+sql+")", 参数)
				}
			}

			if _, 存在 := 请求.J节点请求数据["tags"]; 存在 {
				条件.T添加原始条件("json_extract(tags,'$') like ?", "%"+gconv.String(请求.J节点请求数据["tags"])+"%")
				delete(请求.J节点请求数据, "tags")
			}

			条件.T添加原始条件("drop_at is null and group_id in (select group_id from group_user where user_id = ? )", []string{用户.用户ID})
		} else {
			条件.T添加原始条件("drop_at is null and group_id in (select group_id from group_user where user_id = ? )", []string{用户.用户ID})
		}

	case "Note":
		条件.T添加条件("group_id", 用户.用户ID)

		if 请求.Q请求方法 == http.MethodGet {
			if _, 存在 := 请求.J节点请求数据["tag"]; 存在 {
				条件.T添加原始条件("json_extract(tags,'$') like ?", "%"+gconv.String(请求.J节点请求数据["tag"])+"%")
				delete(请求.J节点请求数据, "tag")
			}

			if _, 存在 := 请求.J节点请求数据["q"]; 存在 {
				条件.T添加原始条件("json_extract(content,'$.markdown') like ?", "%"+gconv.String(请求.J节点请求数据["q"])+"%")
				delete(请求.J节点请求数据, "q")
			}
		}
	case "AppList":
		条件.T添加条件("user_id", 用户.用户ID)

	case "Config":
		条件.T添加条件("for_id", 用户.用户ID)
		条件.T添加条件("for", "user")

	case 表群组:
		if 请求.Q请求方法 == http.MethodGet {
			条件.T添加原始条件("group_id in (select group_id from group_user where user_id = ? )", []string{用户.用户ID})
		}
	}
	return nil
}
